"""
4.1 创建字典
本小节主要学习字典的基本定义、字典的特性以及如何创建字典，重点学习创建字典的
不同方法，通过示例掌握字典的应用场景，更好地为真实事物建立模型。
"""
"""
通过上述示例可以发现，列表不能直观地体现出两个元素之间的联系，不适合存储有对
应关系（映射）的数据，而字典的出现很好地解决了这个问题。字典使用项（item，也称为
“键值对”或者 “元素”）来存储数据，键（key）与值（value）之间用冒号“：”分隔，每
个项之间用逗号“，”隔开，使用大括号“{}”来包含整个字典，其语法格式如下：
字典变量名 = {键 1:值 1, 键 2:值 2, … , 键 N:值 N}
注意：键，必须是唯一、不可变的，即：每个键必须是不同的，键必须是不可变的数据
结构或对象，如字符串、整型等；值，可以是任何类型，不同的键可以对应相同的值。
"""
"""
[练习1]学生字典
"""
person_dict = {
    'name' : '张三',
    'age': 20,
    'height': 180,
    'weight':150,
    'in_class': 'bc211'
}

"""
练习2: 学生对应课程的成绩
"""
student_grade_dict =  {'高数': 95, '英语': 87, 'Python': 90}
print(type(student_grade_dict))
print(student_grade_dict)
print("*" * 100)

"""
4.1.2 字典的无序性
字典中的项，是没有顺序的，即无序的，因此，字典不能像列表一样，使用索引来访问
其中的元素。
"""
student_info_dict = {'姓名': '唐小燕', '提前招生': False, '入学名次': 5}
student_info_dict2 =  {'提前招生': False, '入学名次': 5, '姓名': '唐小燕'}
print(student_info_dict == student_info_dict2)
print("*" * 100)


"""
4.1.4 使用内置函数 dict()创建字典
本知识点主要学习如何使用带不同参数的内置函数 dict()创建字典。通过内置函数 dict()
创建字典时，需要注意该函数使用的参数，参数不同，创建字典的方法也不同。
参数为空，dict()函数的语法格式如下：
字典变量名 = dict()
参数为映射函数，dict()函数的语法格式如下：
字典变量名 = dict(映射函数) 
参数为可迭代对象，dict()函数的语法格式如下：
字典变量名 = dict(可迭代对象) 
参数为关键字参数表，dict()函数的语法格式如下：
字典变量名 = dict(关键字参数表)
1. dict()函数的参数为空
dict()函数的参数为空，用来创建空字典。
"""

my_dict = dict()
print(type(my_dict))
print("*" * 100)


"""
2. dict()函数的参数为映射函数
映射函数是指具有映射功能的函数，如 zip()函数，dict()函数可以使用映射函数作为参
数，以创建字典。
"""
"""
【示例 4.1.4.2】使用映射函数作为 dict()函数的参数，将两个列表合并更改为字典。
"""
coures_list =  ['高数', '英语', 'Python']
grades_list = [95, 87, 90]
grades_dict = dict(zip(coures_list, grades_list))
print(grades_dict)
print("*" * 100)
"""
【代码分析】第 1-2 行代码分别为学生的课程列表和成绩列表。
第 3 行代码中的 dict()函数，将映射函数 zip()作为参数来创建字典。字典的键为 zip()函数中
的第一个对象 studentCoursesList，字典的值为 zip()函数的第二个对象 studentGradesList，键与值
按列表顺序一一对应，即：“高数”对应“95”，“英语”对应“87”，“Python”对应“90”。 第 4 行代码打印输出学生课程成绩字典。

"""
"""
【示例 4.1.4.3】将列表作为可迭代对象，使用 dict()函数生成学生个人信息的字典。
"""
name_tuple = ('姓名','张三')
height_tuple = ('身高',170)
major_tuple = ('专业',"区块链")
student_list = [name_tuple, height_tuple, major_tuple]
student_info_dict = dict(student_list)
print(student_info_dict)
print("*" * 100)


"""
4.2 访问字典
本小节主要学习如何获取字典的长度，如何访问字典键、值及项。Python 语言中的字典，
是无序的数据结构，可以存储任意多个键值对。
4.2.1 字典长度
字典的长度，是指字典中键值对的个数，如果是空字典，那么字典的长度为 0。Python
语言中，提供了内置函数 len()来计算字典的长度，其语法格式如下：
字典长度变量名 = len(字典变量名)
"""
"""
【示例 4.2.1.1】使用 len()函数计算班级中学生的个数。
"""
student_dict = {'姓名':"张三", '身高':'180','体重':80}
print(f'学生信息字典长度是: {len(student_dict)}')
# 如果将student_dict内容清空的话，可以用if判断字典是否变化
student_dict = {}
if len(student_dict) == 0:
    print(f"当前字典内容为空, 长度为: {len(student_dict)}")

print("*" * 100)


"""
4.2.2 字典的访问
本知识点主要学习字典访问与列表访问的不同之处，以及字典的访问方法。
1. 获取字典的键、值和键值对
在 Python 语言中，可以通过字典的常用方法获取字典的键、值和键值对。
获取字典中所有的键，并将其存储在列表中，其语法格式如下：
键形成的列表变量名 = 字典变量名.keys()
获取字典中所有的值，并将其存储在列表中，其语法格式如下：
值形成的列表变量名 = 字典变量名.values()
获取字典中所有的键值对，每个键值对形成有两个对象元组：（键，值），并将每个
元组作为元素存储在列表中，其语法格式如下：
键值对形成的列表变量名 = 字典变量名.items()
"""

"""
通过三种方式获取字典的内容
"""
student_dict =  {'姓名': '张三', '提前招生': False, '入学名次': 5}
n_keys = list(student_dict.keys())
print(f'键的内容为: {n_keys}')
n_values = list(student_dict.values())
print(f'字典中所有的值是: {n_values}')
n_items = list(student_dict.items())
print(f'字典中所有信息: {n_items}')
print("*" * 100)

"""
2. 获取字典中键对应的值
第三章中学习了通过“索引”访问列表的元素，那么字典是按照什么来访问字典的值呢？
“键”！字典中的项是无序的，每个项都不能通过索引、切片等方式访问，只能通过键来访问
相应的值。因此，字典的键，必须是唯一的，一个键只能对应一个值。
在 Python 语言中，可以在字典名后加中括号“[]”，在中括号中写入键，从而获取键对应
的值；也可使用字典的 get()方法获取。
字典名后加中括号，使用键获取对应的值，其语法格式如下：
字典变量名[键] 
通过 get()方法，获取键对应的值，其语法格式如下：
字典变量名.get(键)
"""
student_dict =  {'姓名': '张三', '身高': 180, '体重': 80}
student_name = student_dict['姓名']
print(f'学生姓名是: {student_name}')
student_height = student_dict.get('身高')
print(f'学生身高是: {student_height}')
student_weight = student_dict['体重']
print(f'学生体重是: {student_weight}')
print("*" * 100)

"""
4.2.3 字典的“in | not in”运算符
本知识点主要学习如何使用“in | not in”测试关键字是否存在于字典中，若存在，返回
“True”，反之，返回“False”。
字典的项，是以键值对的形式存在的。那么，“in | not in”是用来判断关键字是否存在
于字典的键中，还是存在于字典的值中呢？
答案是：键！
"""
student_dict =  {'姓名': '张三', '身高': 180, '体重': 80}
print('姓名' in student_dict) # 返回True
student_dict_values = student_dict.values()
print(f'student_dict_values的类型是: {type(student_dict_values)}')
value_res = '张三' in student_dict_values
print(f'判断结果是: {value_res}')

student_dict_keys = student_dict.keys()
print(f'student_dict_keys的类型是: {type(student_dict_keys)}')
key_res = '身高' in student_dict_keys
print(f'判断结果是: {key_res}')
print("*" * 100)


"""
4.3 编辑字典
本小节主要学习字典中项的增加、修改和删除。字典是可变的数据结构，Python 中内置
了许多函数和方法，方便地更新字典中存储的数据，满足实际项目中的使用需求。
4.3.1 字典项添加
字典中只需要指定键对应的值，就可以方便地实现项的添加。字典中项的增加，其语法
格式如下：
字典变量名[新键] = 新值
"""
student_dict = {'姓名': '张三', '身高': 180, '体重': 80}
print(f'添加内容前的字典内容是: {student_dict}')
# 先要判断，字典中是否有"性别"这个键，如果没有，就添加，如果有就不做操作
if '性别' not in student_dict:
    student_dict['性别'] = '男'
print(f'添加内容后的字典内容是: {student_dict}')
print("*" * 100)

"""
4.3.2 字典项修改
字典项的修改，与项的增加非常相似，区别在于：修改项时，字典中已存在想要修改的
“键值对”；增加项时，字典中没有相应的“键值对”。字典项的修改，其语法格式如下：
字典变量名[原键] = 新值
"""
student_dict = {'姓名': '张三', '身高': 180, '体重': 80}
print(f'修改内容前的字典内容是: {student_dict}')

# 先要判断，字典中是否有"体重"这个键，如果有，就修改，如果没有就不做操作
if '体重' in student_dict:
    student_dict['体重'] = 70
print(f'修改内容前的字典内容是: {student_dict}')
print("*" * 100)


"""
4.3.3 字典项删除
字典项的删除，有多种实现方法，较常用的是使用 del 命令删除指定的键值对，其语法
格式如下：
del 字典变量名[键]
"""
student_dict = {'姓名': '张三', '身高': 180, '体重': 80}
print(f'删除内容前的字典内容是: {student_dict}')
# 这里不加判断语句，因为删除是强制执行的，不管字典中是否存在对应的键名，都要执行
del student_dict['体重']
print(f'删除内容后的字典内容是: {student_dict}')
print("*" * 100)


"""
除了常见的 del 命令可以用来删除字典的项，也可使用 pop()、popitem()、clear()等方法
来删除字典中的键值对。在编程过程中，可能会遇到不同的数据处理情况，可以根据实际需
求选择合适的方法对字典进行操作。
1.从字典中删除指定键对应的项，且返回被删除项的值，其语法格式如下：
字典变量名.pop(键) 
2.从字典中随机删除一个键值对，且返回被删除键值对的键和值组成的元组，其语法
格式如下：
字典变量名.popitem()
3. 清空字典，其语法格式如下：
字典变量名.clear()
4. 删除字典，其语法格式如下：
del 字典变量名
"""
student_dict = {'姓名': '张三', '身高': 180, '体重': 80}
# 1. 使用.pop(键)
print('.pop操作')
value = student_dict.pop('体重')
print(f'执行.pop()操作后，value的值是{value}')

print("*" * 100)
# 2. 使用.popitem()
print('.popitem操作')
student_dict = {'姓名': '张三', '身高': 180, '体重': 80}
n_tuple = student_dict.popitem()
print(f'执行.popitem()操作后，n_tuple的值是{n_tuple}')
print("*" * 100)


#3. 使用.clear()，思考.clear()是对当前字典变量清空，还是会有返回值
print('.clear操作')
student_dict = {'姓名': '张三', '身高': 180, '体重': 80}
n_dict = student_dict.clear()
print(f'n_dict的内容是: {n_dict}')
print(f'student_dict的内容是: {student_dict}')

print("*" * 100)
# 4. 使用del删除变量
print('del操作')
student_dict = {'姓名': '张三', '身高': 180, '体重': 80}
# 直接删除student_dict变量
del student_dict
# print(f'student_dict内容是:{student_dict}') # 这里会报错、
print("*" *100)


"""
4.4 遍历字典
本小节主要学习如何使用循环语句对字典的键、值和项进行遍历，以获取需要操作的数
据。字典的遍历，实质上是先通过字典的 keys()、values()、items()方法获取键、值和项的列
表，然后对新形成的列表进行遍历操作。
4.4.1 键的遍历
本知识点主要学习字典中所有键的遍历，也就是逐个将字典中每个项的键读取出来。在
Python 语言中，可以直接对字典遍历，默认逐个读取字典的键；也可以使用字典的 keys()方
法，获取的字典中所有键组成的列表，然后对这个列表进行遍历。
1. 字典遍历，默认遍历字典中的键，其语法格式如下：
for 变量名 in 字典变量名:
执行语句（缩进代码块）
2. 使用字典的 keys()方法，获取字典中所有键组成的列表，通过对列表的遍历来实现
字典键的遍历，其语法格式如下：
for 变量名 in 字典变量名.keys():
执行语句（缩进代码块）
"""
"""
【示例 4.4.1.1】定义学校的学院人数字典，记录学校中每个学院对应的人数。使用 for
循环遍历字典中的键，且获取键对应的值，也就是打印输出每个学院对应的人数。
"""
dep_dict =  {'软件学院': 2563, '电子工程学院': 2071, '智能装备学院': 1899}
# 这种是通过“键”遍历字典
for key in dep_dict:
    print(f'{key}对应的人数是：{dep_dict[key]}')

# 另外一种写法
print('通过.keys()遍历')
for key in dep_dict.keys():
    print(f'{key}对应的人数是：{dep_dict[key]}')
    
print("*" *100)


"""
4.4.2 值的遍历
通过字典的 values()方法，获取字典中所有值作为元素的列表，遍历字典的值，就是逐
个将该列表中的每个元素读取出来，其语法格式如下：
for 变量名 in 字典变量名.values():
执行语句（缩进代码块）
"""
"""
【示例 4.4.2.1】遍历学校的学院人数字典的值，获取每个学院的人数，以计算学校的学
生总人数。
"""
print('值的遍历练习:')
num = 0 # 人数
dep_dict = {'软件学院': 2563, '电子工程学院': 2071, '智能装备学院': 1899}
for value in dep_dict.values():
    num += value
print(f'总人数为: {num}')
print("*" *100)

"""
4.4.3 项的遍历
本知识点主要学习字典中所有项的遍历，也就是逐个将字典中的键值对读取出来。项的
遍历，通过字典的 items()方法获取字典的键值对组成的列表，该列表的每个元素以元组的形
式返回，每个元组有两个元素：键和值。
在 Python 语言中，可以使用遍历字典的方式逐个读取字典的项，结果以元组形式返回；
也可以使用两个变量，来存储返回的元组中的两个元素，得到独立的键和值。 
1. 遍历时以元组形式存储字典的项，其语法格式如下：
for 变量名 in 字典变量名.items():
执行语句（缩进代码块）
2. 遍历时使用两个变量存储“键”和“值”，其语法格式如下：
for 变量名 1, 变量名 2 in 字典变量名.items():
执行语句（缩进代码块）
"""
print('项的遍历练习:')
dep_dict = {'软件学院': 2563, '电子工程学院': 2071, '智能装备学院': 1899}
for t in dep_dict.items():
    print(t)

for key, value in dep_dict.items():
    print(f'键是:{key}, 值是:{value}')

print("*" *100)


"""
4.5 嵌套字典
本小节主要学习字典和列表的结合使用，即嵌套字典，常见的主要有：列表的元素中有
字典、字典的值中包含列表型数据和字典的值中包含字典型数据。在 Python 语言中，各种
数据结构的结合使用，是学习的重难点之一，只有选择合适的数据结构，才能让 Python 语
言的优势发挥到最大。
4.5.1 字典嵌套在列表中
本知识点主要学习列表的元素为字典的嵌套形式。在软件项目开发中，编程人员经常需
要从数据库中读取数据，读取出来的数据多以列表中嵌套字典的形式存在，其数据形式如下：
嵌套字典的列表变量名 = [{键:值, 键:值, … , 键:值}, 
{键:值, 键:值, … , 键:值},
… , 
{键:值, 键:值, … , 键:值}]
访问列表中嵌套的字典，就需要逐层访问，首先使用索引号访问列表的元素：嵌套字典
的列表变量名[索引值]，获得字典：{键:值, 键:值, … , 键:值}，然后使用字典中的键访问对
应的值，其语法格式如下：
嵌套字典的列表变量名[索引值][键]
"""
student_list = [
    {'姓名': "张三", "学号":1, "专业":"区块链"},
    {'姓名': "李四", "学号":2, "专业":"区块链"},
    {'姓名': "王五", "学号":3, "专业":"区块链"}
]
print('如果要拿第一个学生信息中姓名的内容')
print(student_list[0]["姓名"])
print("*" *100)


"""
4.5.2 列表嵌套在字典中
本知识点主要学习字典的值中嵌套了列表数据。字典的键必须是不可变的，如字符串、
整型等，但是，字典的值，可以是任何数据，如字符串、列表、字典、浮点数、布尔值等。
在存储数据时，列表作为常用数据结构，常常出现在字典的值中，以方便地呈现线性、
有序的数据内容，其数据形式如下：
嵌套列表的字典变量名 = {键 1:值 1, 
键 2: [元素 1, 元素 2, … , 元素 N],
… , 
键 N:值 N}
访问字典中嵌套的列表，需要逐层访问，首先通过字典的键获取对应的值：嵌套字典变
量名 [键]，获得列表：[元素 1, 元素 2, … , 元素 N]，然后使用索引值访问列表中的元素，
其语法格式如下：
嵌套列表的字典变量名 [键] [索引值]
"""
student_dict = {
    '姓名': "张三", 
    "学号":1, 
    "专业":"区块链",
    "课程": ['数学','Python基础','Python高级','数据库','Linux基础']
    }
print('如果要获取学生中的课程信息')
print(student_dict['课程'])
print("*" *100)


"""
4.5.3 字典嵌套在字典中
本知识点主要学习字典的值中有字典数据，其数据形式如下：
嵌套字典的字典变量名 = {键 1:值 1, 
键 2: {键:值, 键:值, … , 键:值},
… , 
键 N:值 N}
访问字典中嵌套的字典，需要逐层访问，首先通过字典的键获取对应的值：嵌套字典变
量名 [键]，获得下一层字典：{键:值, 键:值, … , 键:值}，然后再访问下一层字典中的键对
应的值，其语法格式如下：
嵌套字典的字典变量名 [键] [键]
"""
teacher_dict = {
    '姓名':'陶亚辉',
    '专业':'区块链',
    '学生': {
        '张三': {
            '身高':180,
            '体重':80
        },
        '李四': {
            '身高':170,
            '体重':60
        },
        '王五': {
            '身高':185,
            '体重':90
        }
    }
}

print('获取教师信息中，学生姓名为张三的信息')
print(teacher_dict['学生']['张三'])
print("*" *100)


"""
4.6 字典推导式
本小节主要学习字典推导式的使用。字典推导式，与列表推导式的使用方法类似，可以
方便快速地生成字典。字典推导式的使用，可以将循环和条件判断语句相结合，避免冗长的
代码，从而美化代码、提高效率。
4.6.1 循环模式
本知识点主要学习结合循环语句的字典推导式，其语法格式如下：
字典变量名 = {键:值 for 变量名 in 可迭代对象}
可迭代对象，可以是列表、字典、元组等对象。遍历可迭代对象中的元素，将元素赋值
给变量，字典的“键”和“值”都是该迭代变量的表达式运算结果，从而生成新的字典。
"""
student_list = [
    ('姓名','张三'),
    ('身高',180),
    ('体重',80)
    ]
student_dict = {tuple[0]:tuple[1] for tuple in student_list}
print(f'student_dict的内容为: {student_dict}')









